Detect broken connections using socket peeking#193
Detect broken connections using socket peeking#193florimondmanca wants to merge 11 commits intomasterfrom
Conversation
833ee21 to
2089362
Compare
2089362 to
da665f2
Compare
a2eaa4e to
057be4d
Compare
|
@cdeler @JayH5 Okay, I've revisited the approach for |
efa68d8 to
8c6e722
Compare
JayH5
left a comment
There was a problem hiding this comment.
LGTM. Kinda curious whether a library like Trio would want to include this kind of low-level function.
|
Trio sockets expose a special The implementation is pretty simple, and AFAIK there aren't any compatibility issues or anything: I skimmed #185 but I couldn't really follow what you all were worrying about. If you want to steal that code for non-Trio backends, go for it. Otherwise, I'm not sure what to say b/c I don't know what problem you're trying to solve :-) On Trio though please do call |
|
@njsmith Woops — meant to point you at #182, the original issue. Yeah it's a bit fuzzy, here's a quick run-through… (also helpful so I can validate this is all well-posed…) The problem exposed in #182 is something that came up in urllib3 years ago, which we're vulnerable to as of today: when many files are open and we hit the 1024 fd limit on Unix (512 on Windows), In #185 I explored using the So this PR takes a different approach, peeking onto the socket rather than using any selector. Then since we're able to get a raw socket object from async backends too, we're now using a generic cross-platform helper (the I guess I'm not asking anything here, was just curious what your thoughts would be given your experience with low-level networking via trio. If this still sounds nebulous, then, fair enough. 😄 |
On Unix, On Windows, There are also the fancier even-more-modern syscalls like So I think that six lines of code in Trio will solve all your problems everywhere.
Again, please don't try to pull out raw socket objects on Trio, b/c it breaks testing helpers. If there's something you need that's not available on Trio socket objects, lmk and we'll figure out how to add it. |
|
Original issue fixing could be checked if you add the following test: # conftest.py
@pytest.fixture(scope="function")
def many_files() -> typing.Iterator[None]:
files = []
real_file = tempfile.NamedTemporaryFile(delete=False)
try:
real_file.write(b"some")
real_file.flush()
files.append(real_file.fileno())
for _ in range(1023):
fd = os.dup(real_file.fileno())
files.append(fd)
yield
finally:
for fd in files:
os.close(fd)
os.remove(real_file.name)
# test_interface.py
@pytest.mark.anyio
async def test_dropped_connection_detection_bug(
backend: str, server: Server, many_files
) -> None:
async with httpcore.AsyncConnectionPool(backend=backend) as http:
method = b"GET"
url = (b"http", *server.netloc, b"/")
headers = [server.host_header]
for _ in range(2):
status_code, response_headers, stream, ext = await http.arequest(
method, url, headers
)
await read_body(stream)
assert status_code == 200
assert ext == {"http_version": "HTTP/1.1", "reason": "OK"}
assert len(http._connections[url[:3]]) == 1 # type: ignoreMay be you can add the test to the suite? As an alternative, you can add the |
|
Closing, in favor of #185… :-) |
Fixes #182
Attempts implementing #185 (comment)
Attempt peeking data from the socket to detect whether the connection has reached EOF ("broken connection" / "dropped connection").
Better cross-platform support than the
selectorsalternative here: #185.Follow-ups:
is_connection_dropped()tois_at_eof().